package com.fcg.redis.topone.service.impl;

import com.fcg.redis.rediscommon.util.KeyUtils;
import com.fcg.redis.topone.bean.Goods;
import com.fcg.redis.topone.service.TopOneService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 实现按 月、年、全部 统计手机的出货量
 *
 * @author FCG
 */
@Slf4j
@SuppressWarnings("unchecked")
@Service
public class TopOneServiceImpl implements TopOneService {
    private static final String NAME_SPACE = "TOP_ONE";
    private static DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMM");

    private static List<Goods> goodsList = new ArrayList<>();
    private static Map<String, Goods> goodsMap;
    private static Set<String> goodsIdSet;

    @Resource(name = "redisTemplate")
    private ZSetOperations zSetOperations;

    static {
        goodsList.add(Goods.builder().id("b01").name("Apple iPhone 11").build());
        goodsList.add(Goods.builder().id("b02").name("HUAWEI Mate 30 Pro").build());
        goodsList.add(Goods.builder().id("b03").name("荣耀20S").build());
        goodsList.add(Goods.builder().id("b04").name("一加 OnePlus 7 Pro").build());
        goodsList.add(Goods.builder().id("b05").name("HUAWEI nova 4e").build());
        goodsList.add(Goods.builder().id("b06").name("HUAWEI P30").build());
        goodsList.add(Goods.builder().id("b07").name("小米9").build());
        goodsList.add(Goods.builder().id("b08").name("Redmi K30").build());
        goodsList.add(Goods.builder().id("b09").name("vivo Z5x").build());
        goodsList.add(Goods.builder().id("b010").name("OPPO Reno3 Pro").build());
        goodsMap = goodsList.stream().collect(Collectors.toMap(Goods::getId, goods -> goods));
        goodsIdSet = goodsList.stream().map(Goods::getId).collect(Collectors.toSet());
        log.info("initGoods");
    }

    /**
     * 购买一件商品，将商品信息写入redis中对应的 zSet
     *
     * @param goodsId goodsId
     */
    @Override
    public boolean buy(String goodsId) {
        if (!goodsIdSet.contains(goodsId)) {
            throw new IllegalArgumentException("goods id error:" + goodsId);
        }
        LocalDate today = LocalDate.now();
        String monthKey = getRedisKey(today.getYear(), today.getMonthValue());
        String yearKey = getRedisKey(today.getYear(), 0);
        String allKey = getRedisKey(0, 0);
        //分别增加 月、年、所有 中的数据
        zSetOperations.incrementScore(monthKey, goodsId, 1.0);
        zSetOperations.incrementScore(yearKey, goodsId, 1.0);
        zSetOperations.incrementScore(allKey, goodsId, 1.0);
        // do other thing
        log.info("buy a goods: {}", goodsId);
        return true;
    }

    /**
     * 按 年、月、所有 获取前n个商品的销量
     *
     * @param unit     YEARS、MONTHS、FOREVER
     * @param topCount 前n
     * @return 前n个商品的销量
     */
    @Override
    public List<Goods> topOne(ChronoUnit unit, int topCount) {
        log.info("getTopOne,unit: {},count: {}", unit, topCount);
        LocalDate today = LocalDate.now();
        String key;
        switch (unit) {
            case YEARS:
                key = getRedisKey(today.getYear(), 0);
                break;
            case MONTHS:
                key = getRedisKey(today.getYear(), today.getMonthValue());
                break;
            case FOREVER:
                key = getRedisKey(0, 0);
                break;
            default:
                throw new RuntimeException("unSupport unit: " + unit);
        }
        return getData(key, topCount);
    }

    /**
     * 从zSet中获取数据，并转换成商品实体类
     *
     * @param key      key
     * @param topCount 前n
     * @return 前n个商品的销量
     */
    private List<Goods> getData(String key, int topCount) {
        Set<ZSetOperations.TypedTuple<String>> tuples = zSetOperations.reverseRangeWithScores(key, 0, topCount - 1);
        if (Objects.isNull(tuples)) {
            return Collections.emptyList();
        }
        return tuples.stream()
                .map(
                        tuple -> Goods.builder()
                                .id(tuple.getValue())
                                .name(goodsMap.get(tuple.getValue()).getName())
                                .saleCount(Objects.nonNull(tuple.getScore()) ? tuple.getScore().intValue() : 0)
                                .build()
                ).collect(Collectors.toList());
    }

    /**
     * 将日期格式化为redis中的key
     * 例如，2020年01月，格式化后为 ${NAME_SPACE}:202001
     * 若：year == 0,表示所有，返回 ${NAME_SPACE}:ALL
     * 若：month == 0,表示当年，返回 ${NAME_SPACE}:2020
     *
     * @param year  年
     * @param month 月
     * @return redis中的key
     */
    public String getRedisKey(int year, int month) {
        String dayStr;
        if (year == 0) {
            //所有
            dayStr = "ALL";
        } else {
            if (month == 0) {
                //本年
                dayStr = String.valueOf(year);
            } else {
                //本月
                dayStr = LocalDate.of(year, month, 1).format(formatter);
            }
        }
        return KeyUtils.concat(":", NAME_SPACE, dayStr);
    }

}
